#include "bkwidget.h"
#include "ui_bkwidget.h"
#include <QLabel>
#include <QPainterPath>
#include <QSettings>
#include <transtext.h>
#include <QDesktopServices>
#include <QFileDialog>
#include <QStorageInfo>
#include <QFileInfo>
#include <windows.h>
#include <tlhelp32.h>
#include <QDebug>
#include <QProcess>
#include <QTimer>

QString gInstallDir = "AnycubicPhotonWorkshop";
QString gInstallDirCN = "AnycubicPhotonWorkshop_CN";

BkWidget::BkWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::BkWidget)
{
    ui->setupUi(this);
     // 设置无边框和透明背景
    setWindowFlags(Qt::FramelessWindowHint);
    setAttribute(Qt::WA_TranslucentBackground);
    //ui->frame_2->setStyleSheet("QFrame { bord-Image-color: white; border-radius: 24px; }");

    QGraphicsDropShadowEffect *windowShadow = new QGraphicsDropShadowEffect(this);
    // 阴影多少，留出部分阴影的空间
    windowShadow->setBlurRadius(24);
    windowShadow->setOffset(0);
    ui->frame_2->setGraphicsEffect(windowShadow);
    initSettings();
    initConnection();
    initData();
    initView();
 }

BkWidget::~BkWidget()
{
    delete ui;
}

void BkWidget::showBrowserControl()
{
    ui->widget_2->setVisible(m_bBrowser);
    if(m_bBrowser) {
        this->setFixedSize(660 + 24*2, 600 + 24*2);
    } else {
        this->setFixedSize(660 + 24*2, 480 + 24*2);
    }
}

void BkWidget::initConnection()
{
    connect(ui->agreeCheckBox, &QCheckBox::stateChanged, this, [this](int state){
        if(state == 0)
            ui->installBtn->setEnabled(false);
        else
            ui->installBtn->setEnabled(true);
    });
    connect(ui->installBtn, &QPushButton::clicked, this, &BkWidget::onInstallProgram);
    connect(ui->runBtn, &QPushButton::clicked, this, &BkWidget::onRunProgram);
    connect(ui->stackedWidget, &QStackedWidget::currentChanged, this, [this](){
        if(ui->stackedWidget->currentWidget() == ui->page_installing)
            ui->closeBtn->setEnabled(false);
        else
            ui->closeBtn->setEnabled(true);
    });
    connect(ui->browsers, &QPushButton::clicked, this, [this](){
        QString directory = QFileDialog::getExistingDirectory(nullptr,
            TransString::instance()->selectDir,
           m_installPath,
            QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
        if (!directory.isEmpty()) {
            m_installPath = directory;
            ui->lineEdit->setText(m_installPath);
            dealSelectPath(m_installPath);
        }
    });

    connect(ui->closeBtn, &QPushButton::clicked, this, [this](){
        if(ui->stackedWidget->currentWidget() == ui->page_finish){
            close();
            return;
        }
        showShadow();
        m_messageBox->display(kInstallStop, QPoint(0,0), this->size());
    });

    connect(ui->lineEdit, &QLineEdit::editingFinished, this, [this]() {
        m_installPath = ui->lineEdit->text();
        dealSelectPath(m_installPath);
    });

    connect(ui->lineEdit, &QLineEdit::returnPressed, this, [this]() {
        m_installPath = ui->lineEdit->text();
        dealSelectPath(m_installPath);
    });

    ui->labelOption->installEventFilter(this);
    ui->hideBtn->installEventFilter(this);
}

void BkWidget::setInstallState()
{
    if(ui->agreeCheckBox->isChecked())
        ui->installBtn->setEnabled(true);
    else
        ui->installBtn->setEnabled(false);
}

void BkWidget::initData()
{
    setWindowTitle("AnycubicInstaller");
    // ready
    ui->labelName->setText(m_productName);
    ui->labelVersion->setText(m_productVersion);
    ui->installBtn->setText(TransString::instance()->installNow);
    ui->agreeCheckBox->setText(TransString::instance()->agreeFront);
    ui->agreeCheckBox->setCheckable(true);
    ui->agreeCheckBox->setChecked(true);
    ui->labelAgree->setOpenExternalLinks(true);
    QString linkContent = QString("<a style='color: #3986FF; text-decoration: none' href = https://cloud-platform.anycubic.com/w/p/agreement/#/pages/UserAgreement/UserAgreement>");
    linkContent += TransString::instance()->agreeBack;
    connect(ui->labelAgree, &QLabel::linkActivated, this, [=](QString url){
        QDesktopServices::openUrl(QUrl(m_installLicenseUrl));
    });

    ui->labelAgree->setText(linkContent);
    ui->labelOption->setText(TransString::instance()->moreOptions);
    //ui->browsers->setText(TransString::instance()->browers);
    ui->label_error->setText(TransString::instance()->invalidInstallPath);
    ui->labelInstallationTitle->setText(TransString::instance()->installRequestPath);
    ui->labelInstallationContent->setText(calculateSize(m_packageSize));
    ui->labelAvaliableTitle->setText(TransString::instance()->available);
    dealSelectPath(m_installDefaultPath);
    ui->lineEdit->setText(m_installDefaultPath);
    showBrowserControl();

    // installing, failed, over
    ui->labelInstalling->setText(TransString::instance()->installing + "...");
    ui->labelInstallFailed->setText(TransString::instance()->installFailed);
    ui->runBtn->setText(TransString::instance()->installOver);

    //ui->labelProgressValue->setText(TransString::instance()->installRequestPath);

    ui->labelUpdateApplication->setText(TransString::instance()->updateApplication);
    ui->labelUpdateFailed->setText(TransString::instance()->updateFailed);
    ui->labelUpdateTips->setText(TransString::instance()->updateTips);
    ui->labelUpdateWebsite->setText(TransString::instance()->updateWebsite);

    if(m_shadowFrame == nullptr) {
        m_shadowFrame = new QFrame(this);
        m_shadowLabel = new QLabel(m_shadowFrame);
        m_shadowFrame->setWindowFlags(Qt::FramelessWindowHint);
        m_shadowFrame->setAttribute(Qt::WA_TranslucentBackground);
        m_shadowLabel = new QLabel();
        QVBoxLayout* layout = new QVBoxLayout(m_shadowFrame);
        layout->addWidget(m_shadowLabel);
        layout->setMargin(0);
        m_shadowLabel->setStyleSheet("QLabel{ background-color:#4C1A1A1A; border-radius:24px; border: 0px solid; }");
        //m_shadowLabel->setWindowOpacity(0.3);
        m_shadowLabel->setEnabled(false);
        m_shadowFrame->setVisible(false);
    }

    if(m_messageBox == nullptr) {
        m_messageBox = new MessageInfomation(this);
        m_messageBox->setProductName(m_productName);
        m_messageBox->move((width() - m_messageBox->width()) / 2, (height() - m_messageBox->height()) / 2);
        m_messageBox->setVisible(false);
        connect(m_messageBox, &MessageInfomation::signalCloseType, this, &BkWidget::onCheckProgram);
    }

    bool bExist = isProcessRunning();
    qDebug() << "exsit process!" << bExist;
}

void BkWidget::initView()
{
    ui->labelVersion->setAlignment(Qt::AlignCenter);
    ui->progressBar->setTextVisible(false);
}


void BkWidget::initSettings()
{
    QSettings setting(QApplication::applicationDirPath() + "/product.ini", QSettings::IniFormat);
    setting.setIniCodec("UTF-8");
    setting.beginGroup(CONFIG_GENERAL);
    m_productName = setting.value(CONFIG_PRODUCT_NAME).toString();
    m_productRegion = setting.value(CONFIG_PRODUCT_REGION).toInt();
    m_productProcessName = setting.value(CONFIG_PRODUCT_PROCESS_NAME).toString();
    m_installProgramName = setting.value(CONFIG_INSTALL_PROGRAM_NAME).toString();
    m_productVersion = setting.value(CONFIG_PRODUCT_VERSION).toString();
    m_packageSize = setting.value(CONFIG_PACKAGE_SIZE).toULongLong();
    m_installDefaultPath = setting.value(CONFIG_INSTALL_DEFAULT_PATH).toString();
    m_installLicenseUrl = setting.value(CONFIG_INSTALL_LICENSE_URL).toString();
    m_isntallAppId = setting.value(CONFIG_APP_ID).toString();
    setting.endGroup();

    writeReg();
}

void BkWidget::writeReg()
{
    QString region = (m_productRegion == 0) ? "anycubic_installer" : "anycubic_installer_cn";
    QString regPath = "HKEY_CURRENT_USER\\Software\\" + region;
    QSettings settings(regPath, QSettings::NativeFormat);
     settings.setIniCodec("UTF-16");
    QLocale locale;
    settings.setValue("dispaly_language",  (locale.language() == QLocale::Chinese) ? 1:0);
    settings.setValue("install_directory", m_installPath);
    settings.setValue("display_name", m_productName);
    settings.setValue("run_name", m_productProcessName);
    settings.setValue("application_id", m_isntallAppId + "_is1");
    settings.sync();
    m_productName = QStringLiteral("安装包制作新版方案");
}

void BkWidget::showShadow()
{
    m_shadowFrame->setFixedSize(ui->frame_2->size());
    m_shadowFrame->move(24,24);
    m_shadowFrame->show();
}

bool BkWidget::execInstall()
{
    m_bBrowser = false;
    showBrowserControl();

    if(m_process == nullptr) {
        m_process = new QProcess(this);
    }

    writeReg();
    // 启动程序
    QStringList argments;
    argments << m_installPath << "/VERYSILENT" << "/SUPPRESSMSGBOXES" << "/NORESTART";
    m_process->start(m_installProgramName, argments);
    return true;
}

void BkWidget::onFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
    qInfo() << "exitCode: " << exitCode << "exitStatus: " << exitStatus;
}

bool BkWidget::dealSelectPath(const QString& path)
{
    quint64 size = calculateAvailableSize(path);
    if(size < m_packageSize) {
        ui->label_error->setText(TransString::instance()->invalidInstallPath);
        ui->label_error->setVisible(true);
        return false;
    }

    ui->label_error->setVisible(false);
    ui->labelAvaliableContent->setText(calculateSize(calculateAvailableSize(path)));
    return true;
}

qint64 BkWidget::calculateAvailableSize(const QString& path)
{
    QDir dir(path);
    if(!dir.exists())
        dir.cdUp();
    QStorageInfo storage(dir);
    quint64 avaiableSize = 0;
    if (storage.isValid() && storage.isReady())
        avaiableSize = storage.bytesAvailable();

    return avaiableSize;
}

QString BkWidget::calculateSize(const qint64 &size)
{
    double sizeInGB = static_cast<double>(size) / (1024 * 1024 * 1024);
    double sizeInMB = static_cast<double>(size) / (1024 * 1024);
    double sizeInKB = static_cast<double>(size) / 1024;

    if (sizeInGB >= 1) {
        return QLocale().toString(std::round(sizeInGB * 100) / 100, 'f', 2) + " GB"; // 使用QLocale进行格式化输出，保留两位小数
    } else if (sizeInMB >= 1) {
        return QLocale().toString(std::round(sizeInMB * 100) / 100, 'f', 2) + " MB"; // 使用QLocale进行格式化输出，保留两位小数
    } else {
        return QLocale().toString(std::round(sizeInKB)) + " KB"; // 使用QLocale进行格式化输出，保留整数部分
    }
}

void BkWidget::onRunProgram()
{
    QString path = "\"" + m_installPath + "/Install.bat\"";
    std::wstring cmd = path.toStdWString().c_str();
    std::wstring param = m_productProcessName.toStdWString();
    qDebug() << "cmd: " << cmd;
    ShellExecute(NULL, L"open", cmd.c_str(), param.c_str(), NULL, SW_HIDE);
    close();
}


int BkWidget::checkExsitInstallPath()
{
    if(m_installPath.isEmpty())
        m_installPath = m_installDefaultPath;

    if(!dealSelectPath(m_installPath))
        return -1;

    QDir dir(m_installPath);
    QStringList fileNames = dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
    if(fileNames.size() > 0)
        return -2;

    QString installDirName = (m_productRegion == 0) ? gInstallDir : gInstallDirCN;
    if(!m_installPath.contains(gInstallDir) && !m_installPath.contains(gInstallDirCN))
        m_installPath = m_installPath + "/" + installDirName;

    return 0;
}

bool BkWidget::checkInstallProgram()
{
    QString regPath  = QString("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\") + m_isntallAppId + "_is1";
    QSettings settings(regPath, QSettings::NativeFormat);
    QString value = "";
    value = settings.value("UninstallString", "").toString();
    if(value.isEmpty())
        return false;

    return true;
}

bool BkWidget::isProcessRunning() {
    bool bFind = false;
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        qDebug() << "Failed to create snapshot";
        return bFind;
    }

    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    if (!Process32First(hSnapshot, &pe32)) {
        qDebug() << "Failed to get first process";
        CloseHandle(hSnapshot);
        return bFind;
    }

    do {
        std::wstring name = pe32.szExeFile;
        if(QString::fromStdWString(name) ==m_productProcessName)
            bFind = true;
    } while (Process32Next(hSnapshot, &pe32));

    CloseHandle(hSnapshot);
    return bFind;
}

void BkWidget::onInstallProgram()
{
    ui->installBtn->setEnabled(false);
    // step 1:
    if(isProcessRunning()) {
        showShadow();
        m_messageBox->display(kProgramRunning,  QPoint(0,0), this->size());
        return;
    }

    // step 2:
    int value = checkExsitInstallPath();
    if(value < 0 ) {
        if(value == -2) {
            showShadow();
            m_messageBox->display(kInstallPathExsit,  QPoint(0,0), this->size());
        }

        setInstallState();
        return;
    }

    execInstall();
}

void BkWidget::onCheckProgram(const int msgType, int closeType)
{
    setInstallState();
    m_shadowFrame->setVisible(false);
    if(msgType == kInstallPathExsit) {
        if(closeType != MessageInfomation::kOk) {
            m_bBrowser = true;
            showBrowserControl();
            ui->lineEdit->setFocus();
            return;
        } else {
            execInstall();
        }
    } else if(msgType == kInstallStop) {
        if(closeType == MessageInfomation::kCancel) {
            close();
        }
    } else if(msgType == kInstalledProgram) {
        if(closeType != MessageInfomation::kOk) {
            m_bBrowser = true;
            showBrowserControl();
            ui->lineEdit->setFocus();
            return;
        } else {
            execInstall();
        }
    }
}

void BkWidget::mousePressEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton && event->pos().y() <= 50) {
        // 检查是否点击在标题栏区域
        m_dragging = true;
        m_dragPosition = event->globalPos() - frameGeometry().topLeft();
    }
}

void BkWidget::mouseMoveEvent(QMouseEvent *event) {
    if (m_dragging && (event->buttons() & Qt::LeftButton)) {
        move(event->globalPos() - m_dragPosition);
    }
}

void BkWidget::mouseReleaseEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        m_dragging = false;
    }
}

bool BkWidget::eventFilter(QObject *obj, QEvent *event) {
    if(obj == ui->labelOption || obj == ui->hideBtn) {
        if (event->type() == QEvent::Enter) {
            ui->labelOption->setStyleSheet("QLabel#labelOption { color: #3986FF; }");
            if(m_bBrowser)
                ui->hideBtn->setStyleSheet("QPushButton#hideBtn { border-image:url(:/res/icon_arrow_up_hover.png); }");
            else
                ui->hideBtn->setStyleSheet("QPushButton#hideBtn { border-image:url(:/res/icon_arrow_down_hover.png); }");
            return true;
        }
        else if(event->type() == QEvent::Leave) {
            ui->labelOption->setStyleSheet("QLabel#labelOption { color: #808080; }");
            if(m_bBrowser)
                ui->hideBtn->setStyleSheet("QPushButton#hideBtn { border-image:url(:/res/icon_arrow_up_normal.png); }");
            else
                ui->hideBtn->setStyleSheet("QPushButton#hideBtn { border-image:url(:/res/icon_arrow_down_normal.png); }");
            return true;
        }
        else if(event->type() == QEvent::MouseButtonPress) {
            m_bBrowser = !m_bBrowser;
            showBrowserControl();
            ui->labelOption->setStyleSheet("QLabel#labelOption { color: #1D69E0; }");
            if(m_bBrowser)
                ui->hideBtn->setStyleSheet("QPushButton#hideBtn { border-image:url(:/res/icon_arrow_up_press.png); }");
            else
                ui->hideBtn->setStyleSheet("QPushButton#hideBtn { border-image:url(:/res/icon_arrow_down_press.png); }");
            return true;
        }
    }

    return QWidget::eventFilter(obj, event);
}

bool BkWidget::nativeEvent(const QByteArray &eventType, void *message, long *result) {
    if (eventType == "windows_generic_MSG") {
        PMSG msg = (PMSG)message;
        if (msg->message == WM_USER + 1)  {
            m_totalSize = msg->lParam;
            m_currentSize = msg->wParam;
            if(m_currentSize == m_totalSize)
                return false;
            if(ui->stackedWidget->currentWidget() != ui->page_installing) {
                ui->stackedWidget->setCurrentWidget(ui->page_installing);
                ui->progressBar->setMinimum(0);
                ui->progressBar->setMaximum(100);
            }
            quint64 currentValue = floor(m_currentSize * 1.0 / m_totalSize * 100);
            ui->progressBar->setValue(currentValue);
            ui->labelProgressValue->setText(QString("%1 %2").arg(currentValue).arg("%"));
            ui->progressBar->update();
            qDebug() << "currentSize: " << m_currentSize << "totalSize: " << m_totalSize;
        }
        else if(msg->message == WM_USER + 2) {
            ui->stackedWidget->setCurrentWidget(ui->page_finish);
        }
    }
    return false;
}

